package com.yixing.tech.common.tcp.manage;

import com.yixing.tech.common.tcp.client.NettyTcpClient;
import com.yixing.tech.common.tcp.pc.TcpConsumer;
import com.yixing.tech.common.tcp.pc.TcpProducer;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

import java.util.UUID;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

@Slf4j
public class TcpClientEndpoint {

    @Getter
    private final String eid;

    @Getter
    private volatile boolean connected = false;

    @Setter
    @Getter
    private TcpProducer producer;
    @Setter
    @Getter
    private TcpConsumer consumer;

    private final NettyTcpClient nettyTcpClient;
    
    // 重连相关配置
    private final AtomicBoolean isReconnecting = new AtomicBoolean(false);
    private final ScheduledExecutorService reconnectExecutor = Executors.newSingleThreadScheduledExecutor(r -> {
        Thread t = new Thread(r, "TCP-Client-Reconnect-" + UUID.randomUUID().toString().substring(0, 8));
        t.setDaemon(true);
        return t;
    });
    
    // 重连配置参数
    private final int maxReconnectAttempts = 10;
    private final long reconnectInterval = 5000; // 5秒重连间隔
    
    // 连接参数，用于重连
    private String host;
    private Integer port;

    public TcpClientEndpoint(NettyTcpClient nettyTcpClient) {
        this.eid = UUID.randomUUID().toString().replaceAll("-", "");
        this.nettyTcpClient = nettyTcpClient;
    }

    public TcpClientEndpoint(String eid, NettyTcpClient nettyTcpClient) {
        this.eid = eid;
        this.nettyTcpClient = nettyTcpClient;
    }

    /**
     * 建立TCP连接
     * @param host 服务器主机地址
     * @param port 服务器端口号
     */
    public void connect(String host, Integer port) {
        this.host = host;
        this.port = port;
        
        try {
            nettyTcpClient.connect(host, port);
            connected = true;
            log.info("TCP客户端连接成功，端点ID: {}, 服务器地址: {}:{}", eid, host, port);
        } catch (Exception e) {
            connected = false;
            log.error("TCP客户端连接失败，端点ID: {}, 服务器地址: {}:{}, 错误: {}", eid, host, port, e.getMessage());
            startReconnectProcess();
        }
    }

    /**
     * 断开TCP连接
     */
    public void disconnect() {
        try {
            nettyTcpClient.disconnect();
            connected = false;
            isReconnecting.set(false);
            log.info("TCP客户端连接已断开，端点ID: {}", eid);
        } catch (InterruptedException e) {
            log.error("断开TCP连接时发生中断异常: {}", e.getMessage());
            Thread.currentThread().interrupt();
        }
    }

    /**
     * 发送消息
     * @param message 要发送的消息
     * @throws RuntimeException 发送失败时抛出异常
     */
    public void send(String message) throws RuntimeException {
        // 如果连接不可用，先尝试重连
        if (!isConnectionAvailable()) {
            log.debug("连接不可用，尝试重连，端点ID: {}", eid);
            if (!tryReconnect()) {
                throw new RuntimeException("连接不可用且重连失败，端点ID: " + eid);
            }
        }
        
        // 尝试发送消息，如果失败则重连后重试
        try {
            nettyTcpClient.send(message);
        } catch (Exception e) {
            log.warn("发送消息失败，尝试重连后重发，端点ID: {}, 错误: {}", eid, e.getMessage());
            connected = false;
            
            // 尝试重连
            if (tryReconnect()) {
                try {
                    // 重连成功后重新发送消息
                    nettyTcpClient.send(message);
                    connected = true;
                    log.info("消息重发成功，端点ID: {}", eid);
                } catch (Exception ex) {
                    connected = false;
                    log.error("重发消息仍然失败，端点ID: {}, 错误: {}", eid, ex.getMessage());
                    throw new RuntimeException("发送消息失败且重发失败: " + ex.getMessage());
                }
            } else {
                connected = false;
                throw new RuntimeException("发送消息失败且重连失败: " + e.getMessage());
            }
        }
    }
    
    /**
     * 尝试重连
     * @return 重连是否成功
     */
    private boolean tryReconnect() {
        if (isReconnecting.compareAndSet(false, true)) {
            try {
                log.info("开始重连，端点ID: {}, 服务器地址: {}:{}", eid, host, port);
                nettyTcpClient.reconnect();
                connected = true;
                log.info("重连成功，端点ID: {}", eid);
                return true;
            } catch (Exception e) {
                log.error("重连失败，端点ID: {}, 错误: {}", eid, e.getMessage());
                return false;
            } finally {
                isReconnecting.set(false);
            }
        }
        return false; // 正在重连中，返回false
    }
    
    /**
     * 启动自动重连过程
     */
    private void startReconnectProcess() {
        if (host != null && port != null && isReconnecting.compareAndSet(false, true)) {
            log.info("启动自动重连机制，端点ID: {}, 服务器地址: {}:{}，最大重试次数: {}", 
                    eid, host, port, maxReconnectAttempts);
            
            reconnectExecutor.scheduleWithFixedDelay(() -> {
                if (!connected && !Thread.currentThread().isInterrupted()) {
                    try {
                        log.debug("尝试重连，端点ID: {}", eid);
                        nettyTcpClient.reconnect();
                        connected = true;
                        isReconnecting.set(false);
                        log.info("重连成功，端点ID: {}", eid);
                    } catch (Exception e) {
                        log.warn("重连尝试失败，端点ID: {}，错误: {}", eid, e.getMessage());
                        // 如果重连失败，继续下一次重连尝试
                    }
                }
            }, reconnectInterval, reconnectInterval, TimeUnit.MILLISECONDS);
        }
    }
    
    /**
     * 检查连接是否可用
     * @return 连接是否可用
     */
    public boolean isConnectionAvailable() {
        return connected && nettyTcpClient.getChannel() != null && 
               nettyTcpClient.getChannel().isActive() && nettyTcpClient.getChannel().isOpen();
    }
}
